package org.dea.deploy;

import java.io.File;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.util.Map;
import java.util.Set;

import org.dea.facade.DEAFacades;
import org.dea.interfaces.DistributedEasyAcceptFacade;
import org.dea.mapping.DistributedComponent;
import org.dea.mapping.EasyAcceptMappingReader;
import org.dea.util.GenericCommandLineExecutor;
import org.dea.util.ProcessOutput;

public class ProjectDeploy {
	
	private static final int MAX_ERROR = 5;

	
	public ProcessOutput[] deployAll(String projectPath, String classPath, String mapping, DEAFacades facades ) throws Exception{
		Map<String,DistributedComponent> map = EasyAcceptMappingReader.processMappingFile(mapping);
		return deployAll(projectPath,classPath, map, facades);
	}

	public ProcessOutput[] deployAll(String projectPath, String classPath, Map<String, DistributedComponent> map, DEAFacades facades ) throws Exception, InterruptedException {
		Set<String> keys = map.keySet();
		ProcessOutput[] output = new ProcessOutput[keys.size()];
		
		String seed = "DEA_"+System.currentTimeMillis()+"_"+Math.random();
		String dir = "/tmp/"+seed;
		File tar = this.tarProject(seed, projectPath );
		int i = 0;
		for (String key : keys) {
			DistributedComponent comp = map.get(key);
			this.prepareDir(comp.getHostAddress(), dir);
			this.copyProject(comp.getHostAddress(), dir, tar);
			this.executeMain(comp.getHostAddress(), classPath, dir, facades.getRmiFacade(), comp.getArgs(), comp.getHostPort() );
			i++;
		}
		
		Thread.sleep(2000);
		this.pingAll(map);

		return output;
	}
	

	
	public void shutdownAll( String mapping ) throws Exception{
		Map<String,DistributedComponent> map = EasyAcceptMappingReader.processMappingFile(mapping);
		shutdownAll(map);
	}

	public void shutdownAll(Map<String, DistributedComponent> map) throws InterruptedException {
		Set<String> keys = map.keySet();
		for (String key : keys) {
			DistributedComponent cpm = map.get(key);
	        try{
	        	DistributedEasyAcceptFacade facade = (DistributedEasyAcceptFacade)Naming.lookup("rmi://"+ cpm.getHostAddress() + ":" + cpm.getHostPort() +"/IF"+cpm.getFacade());
	        	facade.distributedEasyAcceptShutdown();
	        } catch (Exception ex){
	        	
	        }
		}
		Thread.sleep(2000);
	}
	
	
	public boolean pingAll( String mapping ) throws Exception{
		Map<String,DistributedComponent> map = EasyAcceptMappingReader.processMappingFile(mapping);
		return pingAll(map);
	}

	public boolean pingAll(Map<String, DistributedComponent> map) throws InterruptedException {
		Set<String> keys = map.keySet();
		for (String key : keys) {
			
			DistributedComponent cpm = map.get(key);
			for (int i = 0; i < MAX_ERROR; i++) {
		        try{
		        	DistributedEasyAcceptFacade facade = (DistributedEasyAcceptFacade)Naming.lookup("rmi://"+ cpm.getHostAddress() + ":" + cpm.getHostPort() +"/IF"+cpm.getFacade());
		        	if( !facade.distributedEasyAcceptPing() ){
		        		return false;
		        	}else{
		        		System.out.println("deployed "+cpm);
		        		break;
		        	}
		        } catch (Exception ex){
		        	if( i==MAX_ERROR-1){
		        		return false;
		        	}else{
			        	Thread.sleep(1000);		        		
		        	}
		        }				
			}

		}
		return true;
	}
	

	
	protected void prepareDir(String host, String dir) throws Exception{
		String[] rmdir = { "ssh", "-x", host, "rm -rf "+dir};
		String[] mkdir = { "ssh", "-x", host, "mkdir "+dir};
		GenericCommandLineExecutor rmExec = new GenericCommandLineExecutor(rmdir);
		GenericCommandLineExecutor mkExec = new GenericCommandLineExecutor(mkdir);
		rmExec.runCommand();
		rmExec.waitFor();
		mkExec.runCommand();
		mkExec.waitFor();
	}
	
	protected File tarProject(String seed, String projectPath) throws Exception{
		File tar = new File("/tmp/"+seed+".tgz");
		String[] tarCompact = {"tar", "cvzfC", tar.getAbsolutePath(), projectPath, "."};
		GenericCommandLineExecutor tarExec = new GenericCommandLineExecutor(tarCompact);
		tarExec.runCommand();
		tarExec.waitFor();
		return tar;
	}
	
	protected void copyProject(String host, String dir, File  tar) throws Exception{
		String[] tarCopy = { "scp" ,  tar.getAbsolutePath(), host+":"+dir };
		String[] tarExtract = { "ssh", "-x", host, "cd "+dir+";tar xvzf /tmp/"+tar.getName() };
		GenericCommandLineExecutor tarCopyExec = new GenericCommandLineExecutor(tarCopy);
		GenericCommandLineExecutor tarExtractExec = new GenericCommandLineExecutor(tarExtract);
		tarCopyExec.runCommand();
		tarCopyExec.waitFor();
		tarExtractExec.runCommand();
		tarExtractExec.waitFor();
	}
	
	protected void executeMain(String host, String classPath, String dir, String mainClass, String args, int port ) throws Exception{
		String[] main = { "ssh", "-x", host, "cd "+dir+";java -cp "+classPath+" "+mainClass+" "+port+" "+args };
		GenericCommandLineExecutor mainExec = new GenericCommandLineExecutor(main);
		mainExec.runCommand();
	}
	

	protected boolean ping(String host, int port, String lookupName ){
		try{
			String uri = "rmi://"+ host + ":" + port +"/"+lookupName;
			DistributedEasyAcceptFacade facade = (DistributedEasyAcceptFacade)Naming.lookup(uri);
			facade.distributedEasyAcceptPing();
			return true;
		}catch(Exception e){
			return false;
		}
	}
	
	protected boolean shutdown(String host, int port, String lookupName ){
		try{
			String uri = "rmi://"+ host + ":" + port +"/"+lookupName;
			DistributedEasyAcceptFacade facade = (DistributedEasyAcceptFacade)Naming.lookup(uri);
			facade.distributedEasyAcceptShutdown();
			return true;
		}catch( RemoteException e ){
			return true;
		}catch (Exception e) {
			return false;
		}
	}

	
	

}
